/**
 * @file DumpLog.h
 * @author 世慷 (shikang999@126.com)
 * @brief 一个简单的日志系统
 * @version 0.1
 * @date 2025-08-07
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#pragma once

#include <mutex>
#include <atomic>
#include <chrono>
#include <vector>
#include <string>
#include <memory>
#include <fstream>
#include <sstream>
#include "LogFun.h"
namespace Log
{

//1. 日志警告级别
enum class LogType_E : uint8_t
{
    Info_E  = 0,
    Warn_E  = 1,
    Error_E = 2
};

//2. 退出码
enum class ExitCode_E : uint8_t
{
    OK_E      = 0,
    Error_E   = 1,
    Nothing_E = 255
};

//3. 日志
struct LogLine_t
{
    LogLine_t(): type(LogType_E::Info_E), exitCode(ExitCode_E::Nothing_E), info(""), cppFile(""), lineNO(0), barIndex(-1)
    {

    }

    LogType_E type;                                 //日志类型
    ExitCode_E exitCode;                            //退出码
    std::string info;                               //内容
    std::string cppFile;                            //代码文件
    uint32_t lineNO;                                //行号
    int32_t barIndex;                               //进度条参数
    std::chrono::_V2::system_clock::time_point time;//日志时间
    std::vector<std::string> vecParam;              //参数
};
using vecLogLine_t = std::vector<std::shared_ptr<LogLine_t>>;

std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, ExitCode_E v);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, double v);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, float v);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, int8_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, int16_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, int32_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, int64_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, uint8_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, uint16_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, uint32_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, uint64_t n);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, const char *s);
std::shared_ptr<LogLine_t> &operator << (std::shared_ptr<LogLine_t> &os, const std::string &s);

//4.
class DumpLog
{
public:
    DumpLog();
    ~DumpLog();

    //设置保存日志文件
    bool setLogFile(const std::string &f);

    //设置是否需要控制台输出
    void setNeedConsolePrint(bool need);
    
    //等待退出,并返回退出码,此函数在整个程序退出前调用
    ExitCode_E waitExit();

    //设置进度条最大值
    void setBarMaxValue(uint32_t v, const std::string &tip = "");

    //进度条值加值
    void addBarValue(uint32_t v);

    //终止进度条
    void stopBar();

    //放入日志
    void pushLog(std::shared_ptr<LogLine_t> &s);

    //获取颜色值
    void getCoutColor(std::string &red, std::string &green, std::string &yellow, std::string &reset) const;

    //获取全局日志
    static DumpLog &getGlobalLog();

private:
    void run();
    void dumpLog();
    void printOnlyInConsole();
    void printOnlyInFile();
    void printInAll();
    inline void dispBar(bool consIsOK, bool fwIsOK, uint8_t n, uint16_t v);
    inline void printBar(const std::shared_ptr<LogLine_t> &ptr, bool consIsOK, bool fwIsOK);
    inline void updateExitCode(const std::shared_ptr<LogLine_t> &ptr);
    inline void normNO(std::ostringstream &ss, uint16_t id) const;
    inline std::string getProgBarStr(uint8_t n) const;

private:
    std::string colorReset_;
    std::string colorRed_;
    std::string colorGreen_;
    std::string colorYellow_;

    bool isResetOut_;//是否重定向输出
    bool needConsolePrint_;//是否需要控制台输出
    ExitCode_E exitCode_;
    std::atomic_bool stop_;
    std::atomic_bool run_;
    std::string logFile_;

    //绘制进度条参数
    uint8_t barUpIndex_;
    std::atomic<uint32_t> barMaxIndex_;
    std::atomic<uint32_t> barCurrentIndex_;
    std::string barTip_;
    
    std::ofstream fw_;
    std::mutex mutexForFw_;
    std::mutex mutexForLine_;
    vecLogLine_t vecUpdateLine_;
    vecLogLine_t vecLogLine_;
};

}

//5.
template <typename... Args>
void printLog(Log::LogType_E type, const std::string &cppFile, int lineNO, const std::string &info, const Args&... otherParams) 
{
    //5.1
    auto ptr     = std::make_shared<Log::LogLine_t>();
    ptr->type    = type;
    ptr->cppFile = cppFile;
    ptr->lineNO  = lineNO;
    ptr->info    = info;
    ptr->time    = std::chrono::system_clock::now();

    //5.2
    ptr = (ptr << ... << otherParams);

    //5.3
    Log::DumpLog::getGlobalLog().pushLog(ptr);
}

//6.
#define LogInfo(value, ...)  printLog(Log::LogType_E::Info_E, __FILE__, __LINE__, value, ##__VA_ARGS__);
#define LogWarn(value, ...)  printLog(Log::LogType_E::Warn_E, __FILE__, __LINE__, value, ##__VA_ARGS__);
#define LogError(value, ...) printLog(Log::LogType_E::Error_E, __FILE__, __LINE__, value, ##__VA_ARGS__);

#define BarInit(maxValue, tip) Log::DumpLog::getGlobalLog().setBarMaxValue(maxValue, tip);
#define BarAdd(v) Log::DumpLog::getGlobalLog().addBarValue(v);
#define BarAddOne() Log::DumpLog::getGlobalLog().addBarValue(1);
#define BarStop() Log::DumpLog::getGlobalLog().stopBar();

//7. 模块耗时统计
#define ModuleFun LogFun f(__FILE__, __func__, __LINE__);